/**
 * MOTOR 2 - RAPID FLASH DYNAMICS
 * Copyright (c) 2007-2008, Michael Baczynski
 * Based on the Box2D Engine by Erin Catto, http://www.box2d.org
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * * Neither the name of the polygonal nor the names of its contributors may be
 *   used to endorse or promote products derived from this software without specific
 *   prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package de.polygonal.motor2.collision.shapes.data
{
	import de.polygonal.motor2.collision.shapes.ShapeTypes;
	import de.polygonal.motor2.math.V2;	
	
	/**
	 * An abstract shape.
	 */
	public class ShapeData
	{	
		private var _restitution:Number;
		private var _friction:Number;
		
		/**
		 * Modeling-space position, x-axis.
		 */
		public var mx:Number;
		
		/**
		 * Modeling-space position, y-axis.
		 */
		public var my:Number;
		
		/**
		 * Modeling-space rotation in radians.
		 */
		public var mr:Number;
		
		/**
		 * The shape's friction (0..1).  
		 */
		public function get friction():Number
		{
			return _friction;
		}
		
		/**
		 * @private
		 */
		public function set friction(val:Number):void
		{
			_friction = (val < 0) ? 0 : (val > 1) ? 1 : val;
		}	 
		
		/**
		 * The shape's restitution (0..1).  
		 */
		public function get restitution():Number
		{
			return _restitution;
		}
		
		/**
		 * @private
		 */
		public function set restitution(val:Number):void
		{
			_restitution = (val < 0) ? 0 : (val > 1) ? 1 : val;
		}
		
		/**
		 * @private
		 */
		public function get density():Number
		{
			return _density;
		};
		
		/**
		 * The shape's density.
		 */
		public function set density(n:Number):void
		{
			_density = n;
			invalidate();
		}
		
		/**
		 * The shape's area.
		 */
		public function get area():Number
		{
			return NaN;
		}
		
		/**
		 * Collision category bits.
		 */
		public var categoryBits:int;
		
		/**
		 * Collision mask bits, the categories that this shape would accept
		 * for collision.
		 */
		public var maskBits:int;
		
		/**
		 * Collision groups allow a certain group of objects to never collide
		 * (negative) or always collide (positive). Non-zero group filtering
		 * always wins against the mask bits.
		 */
		public var groupIndex:int;
		
		/**
		 * @private
		 */
		public var type:int;
		
		/**
		 * @private
		 */
		public var next:ShapeData;
		
		/**
		 * @private
		 */
		protected var _density:Number, _mass:Number, _I:Number;
		
		/**
		 * @private
		 */
		protected var _cm:V2;
		
		/**
		 * @private
		 */
		public function ShapeData(density:Number)
		{
			this.density = density;
			init();
		}
		
		/**
		 * @private
		 */
		public function invalidate():void
		{
			_mass = Number.NaN;
			_I    = Number.NaN;
			_cm   = null;
		}
		
		/**
		 * The shape's mass.
		 */
		public function getMass():Number
		{
			if (_density == 0)
				return 0;
			
			if (isNaN(_mass))
				computeMass();
			
			return _mass;
		}
		
		/**
		 * The shape's moment of inertia.
		 */
		public function getInertia():Number
		{
			if (_density == 0)
				return 0;
			
			if (isNaN(_I))
				computeMass();
			
			return _I;
		}
		
		/**
		 * The shape's center of mass.
		 */
		public function getCM():V2
		{
			if (_cm == null) 
				computeMass();
			
			return _cm;
		}
		
		/**
		 * @private
		 */
		public function getShapeClass():Class
		{
			return null;
		}
		
		/**
		 * @private
		 */
		protected function computeMass():void
		{
		}
		
		/**
		 * @private
		 */
		protected function setType():void
		{
			type = ShapeTypes.UNKNOWN;
		}
		
		private function init():void
		{
			setType();
			
			mx = my = mr = .0;
			friction     = .2;
			restitution  = .0;
			
			categoryBits = 0x0001;
			maskBits     = 0xFFFF;
			groupIndex   = 0;
		}
	}
}